﻿using UnityEngine;
using System.Collections;

public class CameraFollow : MonoBehaviour {
	
	public Transform target;
	public float viewlen;
	public float minDistance;
	public float maxDistance;
	public float TaskviewLen;
	
	public float zoomRate;
	public bool gamemode;
	public bool bLockYaw;
	public float powtimes;
	
	public bool bLockPicth = true;
	public int picth_min = 3;
	public int pitch_max = 90;
	public float picth = 45;
	public float yaw = 45;
	public bool bUseDelay = false;
	public float fFollowSpeed = 2.0f;
	public enum RotationAxes
	{
		MouseXAndY = 0,
		MouseX = 1,
		MouseY = 2
	}
	public RotationAxes axes = RotationAxes.MouseXAndY;
	
	public float sensitivityX = 15f;
	public float sensitivityY = 15f;
	
	//shake
	public float minShakeSpeed = 20.0f;
	public float maxShakeSpeed = 20.0f;
	
	public float minShake = 0.01f;
	public float maxShake = 0.025f;
	
	public float minShakeTimes = 6;
	public float maxShakeTimes = 20;
	
	public float fMoveSpeed = 100.0f;
	
	public float maxShakeDistance = 35.0f;
	public float normalHei = 1.5f;
	public bool shake = false;
	public float shakeSpeed = 2.0f;
	public float cShakePos;
	public float shakeTimes = 8.0f;
	
	private float cShake;
	private float cShakeSpeed;
	private float cShakeTimes;
	
	public float targetHeight;
	
	static CameraFollow instance = null;
	public static CameraFollow GetInstance()
	{
		return instance;
	}
	
	public void Awake()
	{
		instance = this;
		Debug.Log(" 初始化相机 " + this);
	}
	
	//use this for initialization
	void Start()
	{
		instance = this;
	}
	
	public void SetShakeInfo(float _minShake, float _maxShake, float _minTimes, float _maxTimes, float _minSpeed, float _maxSpeed, float _fMaxDistance)
	{
		minShake = _minShake;			//0.05f
		maxShake = _maxShake;			//0.125f
		
		minShakeTimes = _minTimes;		//2
		maxShakeTimes = _maxTimes;		//3
		
		minShakeSpeed = _minSpeed;		//20f
		maxShakeSpeed = _maxSpeed;		//20f
		
		maxShakeDistance = _fMaxDistance;	
	}
	
	public void StartShake(float distance)
	{
		float proximity = distance / maxShakeDistance;
		
		if(proximity > 0)
			return;
		
		proximity = Mathf.Clamp(proximity, 0.0f, 1.0f);
		
		proximity = 1.0f - proximity;
		
		cShakeSpeed = Mathf.Lerp(minShakeSpeed, maxShakeSpeed, proximity);
		shakeTimes = Mathf.Lerp(minShakeTimes, maxShakeTimes, proximity);
		
		cShakeTimes = 0;
		cShakePos = Mathf.Lerp(minShake, maxShake, proximity);
		
		shake = true;
	}
	
	private void HandleCameraShake()
	{
		targetHeight = 0;
		if(shake)
		{
			cShake += cShakeSpeed * Time.deltaTime;
			
			if(Mathf.Abs(cShake) > cShakePos)
			{
				cShakeSpeed *= -1.0f;
				cShakeTimes++;
				
				if(cShakeTimes >= shakeTimes)
				{
					shake = false;
				}
				
				if(cShake > 0.0f)
				{
					cShake = maxShake;
				}
				else
				{
					cShake = -maxShake;
				}
			}
			targetHeight += cShake;
		}
	}
	
	public int rotmouse = 1;		//默认右键
	int savedmousex;
	int savedmousey;
	
	public GameObject box_cam;
	public bool bZooming = false;	//正在
	public bool bZoomIn = false;
	public bool bLockMouseScroll = false;
	
	public delegate void OnEndCallback();
	OnEndCallback onend;
	
	public bool PlayAni(string aniname, OnEndCallback _onend = null)
	{
		StopAni();
		
		onend = _onend;
		
		if(animation == null)
		{
			Debug.Log("没有动作组件");
			return false;
		}
		
		if(animation[aniname] == null)
		{
			Debug.Log("没有动作名称" + aniname);
			return false;
		}
		
		bPlayingAni = true;
		Invoke("StopAni", animation[aniname].length);
		animation.Play(aniname);
		return true;
	}
	
	public void StopAni()
	{
		CancelInvoke("StopAni");
		
		if(animation != null)
			animation.Stop();
		
		bPlayingAni = false;
		if(onend != null)
		{
			onend();
		}
	}
	
	public delegate void VoidDelegate();
	public VoidDelegate onViewChanged;
	
	private Vector3 lastPosition;
	private Quaternion lastRotation;
	
	public bool bPlayingAni = false;
	
	void LateUpdate()
	{
		if(bPlayingAni)
			return;
		
		if(target == null)
			return;
		
		if(bZooming)
		{
			if(bZoomIn)
			{
				viewlen = Mathf.Clamp(viewlen, minDistance, TaskviewLen);
				viewlen -= Time.deltaTime * zoomRate / 2;
				if(viewlen < minDistance)
				{
					viewlen = minDistance;
				}
			}
			else
			{
				viewlen += Time.deltaTime * zoomRate * 2;
				if(viewlen > maxDistance)
				{
					bZooming = false;
					viewlen = maxDistance;
				}
			}
			
			if(gamemode)
				Comp();
		}
		else
		{
			HandleCameraShake();
			
			if(gamemode)
			{
				if(Input.GetMouseButton(rotmouse))
				{
					if(axes == RotationAxes.MouseXAndY)
					{
						if(!bLockYaw)
						{
							yaw = yaw + (Input.GetAxis("Mouse X") * sensitivityX);
						}
						if(!bLockPicth)
						{
							picth = picth - (Input.GetAxis("Mouse Y") * sensitivityY);
						}
					}
				}
				
				float dis = Vector3.Distance(transform.position, target.position);
				float fss = 0;
				if(!bLockMouseScroll)
				{
					fss = Input.GetAxis("Mouse ScrollWheel");
				}
				if(fss != 0)
				{
					viewlen -= fss * Time.deltaTime * zoomRate * Mathf.Max(dis, 1.0f) * Mathf.Sqrt(Mathf.Abs(viewlen));
				}
				if(minDistance != maxDistance)
					viewlen = Mathf.Clamp(viewlen, minDistance, maxDistance);
				
				Comp();
			}
		}
		
		if(lastPosition != transform.position || lastRotation != transform.rotation)
		{
			lastPosition = transform.position;
			lastRotation = transform.rotation;
			
			if(onViewChanged != null)
				onViewChanged();
		}
	}
	
	public void MoveToTag()
	{
		bool oldv = bUseDelay;
		bUseDelay = false;
		Comp();
		bUseDelay = oldv;
	}
	
	public bool useNPicth = true;			//默认是有弧度的pitch
	public void Comp()
	{
		if(target != null)
		{
			Vector3 npos = new Vector3();
			float dis_cur = viewlen - minDistance;
			float dis_max = (maxDistance - minDistance);
			float nv = dis_cur / dis_max;
			float val = Mathf.Cos(Mathf.Pow(nv, powtimes));
			picth = Mathf.Min(picth, pitch_max);
			
			picth = Mathf.Max(picth, picth_min);
			
			Quaternion rotation = Quaternion.identity;
			if(!useNPicth)
			{
				nv = 0;
			}
			
			float npicth = Mathf.Lerp(picth, 0, 1 - nv);
			rotation = Quaternion.Euler(npicth, yaw, 0);
			
			Vector3 position = new Vector3();
			if(box_cam)
			{
				//如果受到BOX 的限制
				
				float nlen = viewlen;
				RaycastHit hitInfo = new RaycastHit();
				Ray ray = new Ray();
				
				ray.origin = target.position - transform.forward * 500;
				ray.direction = transform.forward;
				
				LayerMask v = 1 << LayerMask.NameToLayer("box_cam");
				if(Physics.Raycast(ray, out hitInfo, 1000, v))
				{
					float nvi = Vector3.Distance(hitInfo.point, target.position) * 0.9f;
					
					nlen = Mathf.Min(Mathf.Max(0.01f, nvi), viewlen);
					float ndis_cur = Mathf.Max(0, nlen - minDistance);
					float ndis_max = (maxDistance - minDistance);
					float nnv = ndis_cur / ndis_max;
					float nval = Mathf.Cos(Mathf.Pow(nnv, powtimes));
					
					position = rotation * new Vector3(0, 0, -nlen) + target.position + new Vector3(0, targetHeight + 1.5f * (1.0f - 0), 0);
				}
				else
				{
					Debug.LogError("出错了！");
					position = rotation * new Vector3(0, 0, -nlen) + target.position;
				}
			}
			else
			{
				position = rotation * new Vector3(0, 0, -viewlen) + target.position + new Vector3(0, targetHeight + normalHei * (1.0f - nv), 0);
			}
			
			transform.rotation = rotation;
			if(bUseDelay)
			{
				Vector3 npost = position;
				float dis = Vector3.Distance(transform.position, position);
				if(dis > 0.01f)
				{
					Vector3 dir = position - transform.position;
					npost = transform.position + dir.normalized * Mathf.Min(dis, dir.magnitude * fMoveSpeed * Time.deltaTime);
				}
				
				transform.position = npost;
			}
			else
			{
				transform.position = position;
			}
		}
	}
}
